package cn.com.zsw.gblog.config.security;

import cn.com.zsw.gblog.config.cache.RedisCache;
import cn.com.zsw.gblog.modules.common.service.CaptchaService;
import cn.com.zsw.gblog.modules.user.dto.LoginUserDTO;
import cn.hutool.http.ContentType;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Validation;

/**
 * @Author ：shiwangzhou
 * @Date ：Created in 2020-09-15 22:02
 * @Description：
 */
@Slf4j
@Component
public class AdminAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
    @Autowired
    RedisCache redisCache;
    @Autowired
    CaptchaService captchaService;

    /**
     * @param authenticationManager:             认证管理器
     * @param adminAuthenticationSuccessHandler: 认证成功处理
     * @param adminAuthenticationFailureHandler: 认证失败处理
     */
    public AdminAuthenticationProcessingFilter(CusAuthenticationManager authenticationManager, AuthenticationSuccessHandler adminAuthenticationSuccessHandler, AdminAuthenticationFailureHandler adminAuthenticationFailureHandler) {
        super(new AntPathRequestMatcher("/login", "POST"));
        this.setAuthenticationManager(authenticationManager);
        this.setAuthenticationSuccessHandler(adminAuthenticationSuccessHandler);
        this.setAuthenticationFailureHandler(adminAuthenticationFailureHandler);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (request.getContentType() == null || !request.getContentType().contains(ContentType.JSON.toString())) {
            throw new AuthenticationServiceException("请求头类型不支持: " + request.getContentType());
        }

        UsernamePasswordAuthenticationToken authenticationToken;
        try {
            HttpServletRequestWrapper httpServletRequestWrapper = new HttpServletRequestWrapper(request);


            String contentType = request.getContentType();
            logger.info(ContentType.JSON);
            Assert.notNull(contentType, "只接受post json 请求");
            Assert.isTrue(contentType.contains(ContentType.JSON.toString()), "只接受post json 请求");
            LoginUserDTO loginUser = new ObjectMapper().readValue(request.getInputStream(), LoginUserDTO.class);
            Validator validator = new SpringValidatorAdapter(Validation.buildDefaultValidatorFactory().getValidator());
            BindingResult bindingResult = new BindException(loginUser, "loginUser");
            validator.validate(loginUser, bindingResult);
            Assert.isTrue(!bindingResult.hasErrors(),"数据校验失败");
            Assert.isTrue(captchaService.verifyCode(loginUser.getState(), loginUser.getCaptcha()), "验证码校验失败");

            authenticationToken = new UsernamePasswordAuthenticationToken(loginUser.getUsername(), loginUser.getPassword(), null);
            authenticationToken.setDetails(authenticationDetailsSource.buildDetails(httpServletRequestWrapper));
        } catch (Exception e) {
            throw new AuthenticationServiceException(e.getMessage());
        }
        return this.getAuthenticationManager().authenticate(authenticationToken);
    }

}